/**
 * @Author yang
 * @Description //TODO
 * @Date 2020/12/23
 * @Time 9:58
 **/
package goredis

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

type RedisClient struct {
	Pool        *redis.Client `comment:"连接池" json:"pool"`
	RedisHost   string        `comment:"连接地址" json:"redis_host"`
	RedisDb     int           `comment:"数据库" json:"redis_db"`
	MaxIdle     int           `comment:"最大空闲连接数" json:"max_idle"`
	MaxActive   int           `comment:"最大连接数" json:"max_active"`
	IdleTimeout time.Duration `comment:"超时时间" json:"idle_timeout"`
	Password    string        `comment:"redis密码" json:"password"`
}

var RedisPool = &RedisClient{
	Pool:        nil,
	RedisHost:   "127.0.0.1:6379",
	RedisDb:     2,
	MaxIdle:     6,
	MaxActive:   8,
	IdleTimeout: 180,
	Password:    "",
}

var ctx = context.Background()
var client *redis.Client

func init() {
	// 客户端是Redis客户端，代表零个或多个基础连接池。 对于多个goroutine并发使用是安全的。
	rdb := redis.NewClient(&redis.Options{
		Addr:         RedisPool.RedisHost,
		Password:     RedisPool.Password, // no password set
		DB:           RedisPool.RedisDb,  // use default DB
		MinIdleConns: RedisPool.MaxIdle,
		PoolSize:     RedisPool.MaxActive,
		IdleTimeout:  time.Second * time.Duration(RedisPool.IdleTimeout), // 单位: 秒
	})
	client = rdb
	RedisPool.Pool = rdb
}

// Get 取值
func Get(key string) (res string, err error) {
	res, err = client.Get(ctx, key).Result()
	if err == redis.Nil {
		err = errors.New("key2 does not exist")
	}
	return
}

// Set 存值
func Set(key string, val interface{}) (err error) {
	err = client.Set(ctx, "key", "value", 0).Err()
	return
}

// SetWithEx  SET key value EX 10 NX 仅当当前键不存在时存值, 带过期时间(单位:秒, 0 表示永不过期)
func SetWithEx(key string, val interface{}, expiredSec int) (err error) {
	res, resErr := client.SetNX(ctx, key, val, time.Duration(expiredSec)*time.Second).Result()
	if resErr != nil {
		err = resErr
		return
	}
	if !res {
		err = errors.New(fmt.Sprintf("您要保存的键 [%v] 已经存在!", key))
	}
	return
}

// Eval 用于执行 lua 脚本, 调用处自行处理执行结果
func Eval(scriptStr string, keys []string, args ...interface{}) (res interface{}, err error) {
	res, err = client.Eval(ctx, scriptStr, keys, args).Result()
	return
}

// Do 自定义命令执行, 调用处自行处理执行结果
func Do(command, key string, args ...interface{}) (res interface{}, err error) {
	argPrefix := []interface{}{command, key}
	argPrefix = append(argPrefix, args...)
	res, err = client.Do(ctx, argPrefix...).Result()
	return
}
